import { CompressionSpec } from './CompressionSpec';
import { ObservationSpec } from './ObservationSpec';
import { ObservationWriter } from './ObservationWriter';

/**
 * 观察结果（Observations）的维度（Dimension）属性标志
 */
export enum DimensionProperty {
	/**
	 * 没有指定属性标志
	 */
	Unspecified = 0,

	/**
	 *没有哪个维度上的观察到的属性，观测可用用完全连接的网络去进行处理
	 */
	None = 1,

	/**
	 * 意味着在这个维度上用卷积（convolution）是适合的
	 */
	TranslationalEquiveriance = 2,

	/**
	 * 意味着在这个维度上可以有不同数量（variable number）的观察者
	 */
	VariableSize = 4,
}

/**
 * 传感器的观察者类型
 */
export enum ObservationType {
	/**
	 *收据到的观察结果是通用的（generic）
	 */
	Default = 0,

	/**
	 * 收据到的观测值包含目标信（goal）息
	 */
	GoalSignal = 1,
}

/**
 * 用户生成观察结果的传感器接口
 */
export interface ISensor {
	/**
	 * 返回将由传感器生成的观测值的描述（description）
	 * @returns 描述观察结果的对象
	 */
	getObservationSpec(): ObservationSpec;

	/**
     * 
        将观测数据直接写入{@see ObservationWriter" }。 
        请注意，这(和 {@see GetCompressedObservation })可能 
        每个代理步骤调用多次，因此不应改变任何内部状态。
     * @param writer 观测结果将要被写入哪里
        @returns 写入元素的数量
     */
	write(writer: ObservationWriter): number;

	/**
	 * 返回观测值的压缩（compressed）表示形式。
	 * 对于小的观察，一般不应该这样做。
	 * 然而，压缩大型观测值(如视觉结果)可以显著提高模型训练时间(training time)。
	 * @returns
	 */
	getCompressedObservation(): Uint8Array;

	/**
	 * 更新传感器的所有内部状态，每个代理每一步都会调用
	 */
	update(): void;

	/**
	 *重置传感器内部状态，这个是每个代理结束时调用。大部分实现着可是将方法保留为空
	 */
	reset(): void;

	/**
	 * 返回正在使用的压缩类型的信息。如果没有使用压缩，返回默认值
	 * @returns 描述传感器使用的压缩对象
	 */
	getCompressionSpec(): CompressionSpec;

    /**
     * 获取传感器的名称。这用于确保代理上传感器的确定性排序，因此所有传感器和代理之间的命名必须一致。
     */
    getName():string;

}

export class SensorExtensions{
    static observationSize(sensor:ISensor){
        const obsSpec = sensor.getObservationSpec();
        let count = 1;
        for (let i = 0; i < obsSpec.rank; i++) {
            count *= obsSpec.shape[i];
            
        }
        return count;
    }
}


export class SensorUtils{

    static sortSensors(sensors:ISensor[]){
        sensors.sort((x,y) => x.getName().localeCompare(y.getName(),undefined, { sensitivity: 'base' }));
    }
}